home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / prog / amisl090.zip / NOTE.ASM < prev    next >
Assembly Source File  |  1992-09-12  |  26KB  |  1,010 lines

  1. ;-----------------------------------------------------------------------
  2. ; NOTE.ASM    Public Domain 1992 Ralf Brown
  3. ;        You may do with this software whatever you want, but
  4. ;        common courtesy dictates that you not remove my name
  5. ;        from it.
  6. ;
  7. ; Popup to append one or more lines to a text file.  Demonstration of the
  8. ; use of DOS from within an AMIS-compliant TSR.
  9. ; Note: popup may be done from the commandline or via a hotkey; however,
  10. ;     the hotkey support requires a newer BIOS which has the INT 15/4F
  11. ;    keyboard intercept
  12. ;
  13. ; Version 0.90
  14. ; LastEdit: 9/10/92
  15. ;-----------------------------------------------------------------------
  16.  
  17. __TINY__ equ 1                ; using Tiny model
  18.     INCLUDE AMIS.MAC
  19.  
  20.     @Startup 3,00            ; need DOS 3.00
  21.                     ; this macro also takes care of declaring
  22.                     ; all the segments in the required order
  23.  
  24. ;-----------------------------------------------------------------------
  25. ;
  26. VERSION_NUM equ 005Ah    ; v0.90
  27. VERSION_STR equ "0.90"
  28.  
  29. ; uncomment the following line to use the generic hotkey dispatcher, at a cost
  30. ; of an additional 80 bytes
  31. ;CUSTOM_HOTKEY_CODE equ 1
  32.  
  33. WINDOW_TOP    equ 0        ; topmost row of TSR's popup window
  34. WINDOW_LEFT   equ 5        ; leftmost column of TSR's popup window
  35. WINDOW_HEIGHT equ 3           ; height (including frame) of popup window
  36. WINDOW_WIDTH  equ 70          ; width (including frame) of popup window
  37. LOCAL_STACK_SIZE equ 128    ; size of local stack in bytes
  38. HOTKEY_SCAN   equ SCAN_N    ; scan code for 'N' key
  39. HOTKEY_NAME   equ "N"
  40.  
  41. LODSB_ES MACRO
  42.     DB 26h,0ACh    ; LODSB ES:
  43.     ENDM
  44.  
  45. ;-----------------------------------------------------------------------
  46. ; Put the resident code into its own segment so that all the offsets are
  47. ; proper for the new location after copying it into a UMB or down into
  48. ; the PSP.
  49. ;
  50. TSRcode@
  51.  
  52. ;-----------------------------------------------------------------------
  53. ; Since we need a PSP, but might be loaded into a UMB or at the top of
  54. ; conventional memory, we make a copy of the all-important first 64 bytes
  55. ; of the PSP here.  After relocation, this copy will start at offset 0
  56. ;
  57. TSR_PSP    db 64 dup (?)
  58.  
  59. ;-----------------------------------------------------------------------
  60. ; TSR's initialized data storage
  61. ;
  62. TSRdata@
  63. TSR_name    db "NOTE",0        ; title for popup window
  64.  
  65. int13_25_busy label word    ; allow both to be tested in one operation
  66. int13_busy    db 0
  67. int25_busy    db 0
  68. int26_TSR_busy label word    ; allow both to be tested in one operation
  69. int26_busy    db 0
  70. TSR_activated    db 0
  71. want_popup    db 0
  72. want_shutdown    db 0
  73. popup_INT28    db 0
  74.  
  75. ;;; add TSR-specific initialized data below
  76.  
  77. CRLF_buffer    db 13,10
  78.  
  79. TSRdataEnd@
  80.  
  81. ;-----------------------------------------------------------------------
  82. ; TSR's uninitialized data storage
  83. ;
  84. TSRbss@
  85. INDOS_ptr    dd ?
  86. CRITERR_ptr    dd ?
  87. interrupted_DTA    dd ?
  88. interrupted_PSP dw ?
  89. interrupted_SP    dw ?
  90. interrupted_SS    dw ?
  91.  
  92. interrupted_cursorpos dw ?
  93. display_page_attr label word
  94. display_attr    db ?
  95. display_page    db ?
  96. screen_width    db ?
  97.  
  98. cursor_pos label word
  99. cursor_x    db ?
  100. cursor_y    db ?
  101.  
  102. screen_buffer     db (WINDOW_HEIGHT*WINDOW_WIDTH*2) dup (?)
  103. local_stack     db LOCAL_STACK_SIZE dup (?)
  104. local_stack_bottom label byte
  105.  
  106. ;;; add TSR-specific uninitialized data below
  107.  
  108. notefile_handle dw ?
  109.  
  110. edit_buffer    db WINDOW_WIDTH-2 dup (?)
  111. TSRbssEnd@
  112.  
  113.  
  114. ;-----------------------------------------------------------------------
  115.  
  116. TSR_main proc near
  117.     ASSUME    DS:TGROUP,ES:NOTHING
  118.     xor    si,si            ; SI stores line length
  119. TSR_main_loop:
  120.     mov    dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
  121.     add    dx,si
  122.     call    TSR_move_cursor
  123.     call    TSR_getkey
  124.     cmp    al,0Dh            ; Enter pressed?
  125.     je    TSR_main_line_end
  126.     cmp    al,27            ; Esc pressed?
  127.     je    TSR_main_done
  128.     cmp    al,8
  129.     je    backspace
  130.     cmp    al,0            ; extended ASCII?
  131.     je    TSR_main_loop        ; if yes, ignore
  132.     cmp    al,0E0h
  133.     jne    got_char
  134.     cmp    ah,0
  135.     jne    TSR_main_loop
  136. got_char:
  137.     cmp    si,WINDOW_WIDTH-2
  138.     jb    store_char
  139. beep:
  140.     mov    ax,0E07h        ; beep
  141.     int    10h
  142.     jmp    TSR_main_loop
  143. store_char:
  144.     mov    edit_buffer[si],al
  145.     inc    si            ; remember that we got another char
  146.     call    TSR_put_char
  147.     jmp    TSR_main_loop
  148.  
  149. backspace:
  150.     or    si,si
  151.     jz    beep
  152.     dec    si
  153.     mov    dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
  154.     add    dx,si
  155.     call    TSR_move_cursor
  156.     mov    al,' '
  157.     call    TSR_put_char
  158.     jmp    TSR_main_loop
  159.  
  160. TSR_main_line_end:
  161.     mov    ah,40h
  162.     mov    bx,notefile_handle
  163.     mov    cx,si
  164.     mov    dx,offset TGROUP:edit_buffer
  165.     int    21h
  166.     mov    ah,40h
  167.     mov    cx,2
  168.     mov    dx,offset TGROUP:CRLF_buffer
  169.     int    21h
  170.     call    TSR_clear_window
  171.     jmp    TSR_main        ; restart for next line
  172.  
  173. TSR_main_done:
  174.     mov    bx,notefile_handle
  175.     mov    ah,45h            ; DUP handle
  176.     int    21h
  177.     jc    TSR_main_exit        ; quit now if unable to duplicate
  178.     mov    bx,ax
  179.     mov    ah,3Eh            ; close duplicate
  180.     int    21h
  181. TSR_main_exit:
  182.     ret
  183. TSR_main endp
  184.  
  185. ;-----------------------------------------------------------------------
  186. ; Function that performs any necessary cleanup prior to the TSR being
  187. ; removed from memory.  At the time it is called, the TSR is effectively
  188. ; popped up, though it has not modified the screen.  If this routine needs
  189. ; to write on the screen, it must save and restore the screen contents
  190. ; itself
  191. ;
  192. TSR_shutdown proc near
  193.     mov    bx,notefile_handle
  194.     mov    ah,3Eh            ; close the file
  195.     int    21h
  196.     ret
  197. TSR_shutdown endp
  198.  
  199. ;-----------------------------------------------------------------------
  200.  
  201. TSR_INT24_handler:
  202.     mov    al,03h            ; FAIL, for now
  203. ;    iret  ; save a byte by falling through to next handler
  204.  
  205. ;-----------------------------------------------------------------------
  206. ; Simply ignore Ctrl-Break and Ctrl-C interrupts
  207. ;
  208. TSR_INT1B_handler:
  209. TSR_INT23_handler:
  210.     iret
  211.  
  212. ;=======================================================================
  213. ; It should not be necessary to make any changes between here and the
  214. ; end of the resident portion (other than the TSR identifier in the ALTMPX
  215. ; macro) in order to modify this code for a different purpose.
  216. ;=======================================================================
  217.  
  218. ;-----------------------------------------------------------------------
  219. ;
  220. TSR_getkey proc near
  221.     mov    ah,11h            ; keystroke available?
  222.     int    16h
  223.     jnz    TSR_getkey_got_one    ; if yes, get it, otherwise
  224.     int    28h            ; give other TSRs a chance to do work
  225.     jmp    TSR_getkey
  226. TSR_getkey_got_one:
  227.     mov    ah,10h            ; get the keystroke
  228.     int    16h
  229.     ret
  230. TSR_getkey endp
  231.  
  232. ;-----------------------------------------------------------------------
  233. ; entry: DH = row, DL = column
  234. ;
  235. TSR_move_cursor proc near
  236.     ASSUME    DS:TGROUP,ES:NOTHING
  237.     mov    cursor_pos,dx
  238.     mov    bh,display_page
  239.     mov    ah,2            ; BIOS move-cursor function
  240.     int    10h
  241.     ret
  242. TSR_move_cursor endp
  243.  
  244. ;-----------------------------------------------------------------------
  245. ; exit: AX,BX,CX,DX destroyed
  246. ;
  247. TSR_put_char_186 proc near
  248.     mov    al,186
  249.     ;; fall through to TSR_put_char
  250. TSR_put_char_186 endp
  251.  
  252. ;-----------------------------------------------------------------------
  253. ; entry: AL = char
  254. ; exit: AH,BX,CX,DX destroyed
  255. ;
  256. TSR_put_char proc near
  257.     mov    cx,1
  258.     ;; fall through to TSR_put_line
  259. TSR_put_char endp
  260.  
  261. ;-----------------------------------------------------------------------
  262. ; entry: AL = char, CX = repeat count
  263. ; exit: AX,BX,CX,DX destroyed
  264. ;
  265. TSR_put_line proc near
  266.     ASSUME    DS:TGROUP,ES:NOTHING
  267.     add    cursor_x,cl
  268.     mov    bx,display_page_attr
  269.     mov    ah,9
  270.     int    10h
  271.     mov    al,cursor_x
  272.     cmp    al,screen_width
  273.     jb    TSR_put_line_done
  274.     mov    cursor_x,0
  275.     inc    cursor_y
  276. ;
  277. ; need to handle case of falling off the bottom
  278. ;
  279.  
  280.  
  281. TSR_put_line_done:
  282.     mov    dx,cursor_pos
  283.     mov    ah,2            ; set cursor position
  284.     int    10h
  285.     ret
  286. TSR_put_line endp
  287.  
  288. ;-----------------------------------------------------------------------
  289.  
  290. save_screen proc near
  291.     ASSUME    DS:TGROUP,ES:NOTHING
  292.     mov    ah,0Fh
  293.     int    10h            ; get video mode and active page
  294.     mov    display_page,bh
  295.     mov    screen_width,ah
  296.     mov    ah,3            ; get cursor position on page BH
  297.     int    10h
  298.     mov    interrupted_cursorpos,dx
  299.     push    ds
  300.     pop    es
  301.     ASSUME    ES:TGROUP
  302.     mov    di,offset TGROUP:screen_buffer
  303.     mov    dh,WINDOW_TOP
  304. save_screen_loop1:
  305.     mov    dl,WINDOW_LEFT
  306. save_screen_loop2:
  307.     mov    ah,2            ; set cursor position on page BH
  308.     int    10h
  309.     mov    ah,8            ; read character&attribute on page BH
  310.     int    10h
  311.     stosw                ; and remember them for later restore
  312.     inc    dl
  313.     cmp    dl,WINDOW_LEFT+WINDOW_WIDTH
  314.     jb    save_screen_loop2
  315.     inc    dh
  316.     cmp    dh,WINDOW_TOP+WINDOW_HEIGHT
  317.     jb    save_screen_loop1
  318.     ret
  319. save_screen endp
  320.  
  321. ;-----------------------------------------------------------------------
  322.  
  323. framed_window_hline proc near
  324.     push    ax
  325.     call    TSR_put_char
  326.     mov    cx,WINDOW_WIDTH-2
  327.     mov    al,205
  328.     call    TSR_put_line
  329.     pop    ax
  330.     mov    al,ah
  331.     jmp    TSR_put_char
  332. framed_window_hline endp
  333.  
  334. ;-----------------------------------------------------------------------
  335.  
  336. framed_window proc near
  337.     ASSUME    DS:TGROUP,ES:NOTHING
  338.     mov    dx,256*WINDOW_TOP + WINDOW_LEFT
  339.     call    TSR_move_cursor
  340.     mov    display_attr,0Fh    ; bright white on black
  341.     mov    ax,0BBC9h        ; double upper left/right corners
  342.     call    framed_window_hline
  343.     push    si
  344.     mov    dx,256*(WINDOW_TOP+1) + WINDOW_LEFT
  345. frame_loop:
  346.     mov    si,dx
  347.     call    TSR_move_cursor
  348.     call    TSR_put_char_186    ; double vertical bar
  349.     mov    dx,si
  350.     mov    dl,WINDOW_LEFT+WINDOW_WIDTH-1
  351.     call    TSR_move_cursor
  352.     call    TSR_put_char_186    ; double vertical bar
  353.     mov    dx,si
  354.     inc    dh
  355.     cmp    dh,WINDOW_TOP+WINDOW_HEIGHT-1
  356.     jb    frame_loop
  357.     pop    si
  358.     mov    dx,256*(WINDOW_TOP+WINDOW_HEIGHT-1) + WINDOW_LEFT
  359.     call    TSR_move_cursor
  360.     mov    display_attr,0Fh    ; bright white on black
  361.     mov    ax,0BCC8h        ; double lower left/right corners
  362.     call    framed_window_hline
  363.     ;
  364.     ; frame is done, now add the title
  365.     ;
  366.     mov    dx,256*WINDOW_TOP + (WINDOW_LEFT+2)
  367.     call    TSR_move_cursor
  368.     mov    si,offset TGROUP:TSR_name
  369. frame_name_loop:
  370.     lodsb
  371.     or    al,al
  372.     jz    frame_name_done
  373.     call    TSR_put_char
  374.     jmp    frame_name_loop
  375. frame_name_done:
  376.     mov    dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
  377.     call    TSR_move_cursor
  378.     mov    display_attr,07h    ; dim white on black
  379.     ;; fall through to TSR_clear_window ;;
  380. framed_window endp
  381.  
  382. ;-----------------------------------------------------------------------
  383.  
  384. TSR_clear_window proc near
  385.     mov    bh,display_attr
  386.     mov    cx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
  387.     mov    dx,256*(WINDOW_TOP+WINDOW_HEIGHT-2) + (WINDOW_LEFT+WINDOW_WIDTH-2)
  388.     mov    ax,0600h        ; clear popup window area
  389.     int    10h
  390.     ret
  391. TSR_clear_window endp
  392.  
  393. ;-----------------------------------------------------------------------
  394.  
  395. restore_screen proc near
  396.     ASSUME    DS:TGROUP,ES:NOTHING
  397.     mov    si,offset TGROUP:screen_buffer
  398.     mov    dh,WINDOW_TOP
  399. rest_screen_loop1:
  400.     mov    dl,WINDOW_LEFT
  401. rest_screen_loop2:
  402.     mov    ah,2
  403.     mov    bh,display_page
  404.     int    10h            ; set cursor position
  405.     lodsw                ; get character and attribute to restore
  406.     mov    bl,ah            ; BL <- attribute
  407.     mov    cx,1
  408.     mov    ah,9            ; write character&attribute
  409.     int    10h
  410.     inc    dl
  411.     cmp    dl,WINDOW_LEFT+WINDOW_WIDTH
  412.     jb    rest_screen_loop2
  413.     inc    dh
  414.     cmp    dh,WINDOW_TOP+WINDOW_HEIGHT
  415.     jb    rest_screen_loop1
  416.     mov    dx,interrupted_cursorpos
  417.     mov    ah,2            ; restore cursor position
  418.     int    10h
  419.     ret
  420. restore_screen endp
  421.  
  422. ;-----------------------------------------------------------------------
  423. ; requires DS = TGROUP and interrupts enabled on entry; may destroy BX
  424. ;
  425. popup proc near
  426.     mov    TSR_activated,1        ; yes, we are now active
  427.     mov    want_popup,0        ; and we are finally popping up
  428.     ;
  429.     ; switch to a local stack so that we are assured of enough stack space
  430.     ;
  431.     push    ax
  432.     mov    interrupted_SS,ss
  433.     mov    interrupted_SP,sp
  434.     mov    ax,cs
  435.     cli
  436.     mov    ss,ax            ; switch stack
  437.     ASSUME    SS:TGROUP
  438.     mov    sp,offset RESIDENT_CODE:local_stack_bottom
  439.     sti
  440.     push    es
  441.     push    di
  442.     push    si
  443.     push    bp
  444.     push    dx
  445.     push    cx
  446.     push    bx
  447.     ;
  448.     ; switch to our own PSP and store current DTA
  449.     ;
  450.     mov    ah,51h
  451.     int    21h            ; get PSP of interrupted program
  452.     mov    interrupted_PSP,bx
  453.     mov    bx,cs
  454.     mov    ah,50h            ; set PSP to our own
  455.     int    21h
  456.     mov    ah,2Fh            ; get DTA
  457.     int    21h
  458.     ASSUME    ES:NOTHING
  459.     mov    word ptr interrupted_DTA,bx
  460.     mov    word ptr interrupted_DTA+2,es
  461.     GRAB_INTERRUPT 1Bh,TSR_INT1B_handler
  462.     GRAB_INTERRUPT 23h,TSR_INT23_handler
  463.     GRAB_INTERRUPT 24h,TSR_INT24_handler
  464.     mov    al,0
  465.     xchg    al,want_shutdown    ; get and clear shutdown flag
  466.     or    al,al            ; was it set?
  467.     jz    do_popup        ; if not, regular popup
  468.     call    TSR_shutdown
  469.     jmp short popup_done
  470. do_popup:
  471.     call    save_screen
  472.     call    framed_window
  473.     call    TSR_main        ; the actual guts of the TSR
  474.     call    restore_screen
  475. popup_done:
  476.     RESTORE_INTERRUPT 1Bh
  477.     RESTORE_INTERRUPT 23h
  478.     RESTORE_INTERRUPT 24h
  479.     ;
  480.     ; restore the original PSP and DTA
  481.     ;
  482.     mov    bx,interrupted_PSP
  483.     mov    ah,50h            ; set PSP back to stored value
  484.     int    21h
  485.     push    ds
  486.     lds    dx,interrupted_DTA
  487.     ASSUME    DS:NOTHING
  488.     mov    ah,1Ah            ; set DTA back to stored value
  489.     int    21h
  490.     pop    ds            ; restore DS
  491.     ASSUME    DS:TGROUP
  492.     pop    bx
  493.     pop    cx
  494.     pop    dx
  495.     pop    bp
  496.     pop    si
  497.     pop    di
  498.     pop    es
  499.     ;
  500.     ; finally, switch back to original stack
  501.     ;
  502.     cli
  503.     mov    ss,interrupted_SS
  504.     ASSUME    SS:NOTHING
  505.     mov    sp,interrupted_SP
  506.     sti
  507.     pop    ax
  508.     mov    TSR_activated,0        ; no longer popped up, so OK to pop again
  509.     ret
  510. popup endp
  511.  
  512. ;-----------------------------------------------------------------------
  513.  
  514. attempt_popup proc near
  515.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  516.     mov    want_popup,1        ; remember that a popup was requested
  517.     ;; fall through to try_popup ;;
  518. attempt_popup endp
  519.  
  520. try_popup proc near
  521.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  522.     pushf
  523.     sti                ; OK to interrupt
  524.     cmp    want_popup,0
  525.     je    try_popup_done
  526.     push    ax
  527.     mov    ax,int13_25_busy    ; check disk activity flags
  528.     or    ax,int26_TSR_busy    ; and whether already popped up
  529.     pop    ax
  530.     jnz    try_popup_done        ; can't popup if any of those flags set
  531.     push    ds
  532.     push    bx
  533.     lds    bx,INDOS_ptr        ; check InDOS flag
  534.     ASSUME    DS:NOTHING
  535.     cmp    byte ptr [bx],1
  536.     jb    try_popup_1        ; if zero, DOS is probably idle
  537.     ja    try_popup_2        ; if not 0 or 1, DOS is definitely busy
  538.     cmp    popup_INT28,0        ; if activated via INT 28, INDOS flag is
  539.     jz    try_popup_2        ; allowed to be 1 rather than 0
  540. try_popup_1:
  541.     lds    bx,CRITERR_ptr        ; InDOS says DOS is idle, but it might
  542.     ASSUME    DS:NOTHING        ;   be in the critical error handler
  543.     cmp    byte ptr [bx],0        ;   so check the CritErr flag
  544.     jne    try_popup_2        ; can't popup if in critical error
  545.     push    cs
  546.     pop    ds            ; restore DS
  547.     ASSUME    DS:TGROUP
  548.     call    popup            ; whew, we made it... we can pop up now
  549. try_popup_2:
  550.     ASSUME    DS:NOTHING
  551.     pop    bx            ; restore registers
  552.     pop    ds
  553.     ASSUME    DS:NOTHING
  554. try_popup_done:
  555.     popf
  556.     ret
  557. try_popup endp
  558.  
  559. ;-----------------------------------------------------------------------
  560.  
  561. API_popup proc near
  562.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  563.     call    attempt_popup
  564.     mov    al,AMIS_POPUP_WILLDO    ; can't pop up now, will do so when able
  565.     cmp    want_popup,1        ; did we manage to pop up?
  566.     je    API_popup_done
  567.     mov    al,AMIS_SUCCESSFUL    ; successful
  568.     xor    bx,bx            ; no return code
  569. API_popup_done:
  570.     ret
  571. API_popup endp
  572.  
  573. ;-----------------------------------------------------------------------
  574.  
  575. remov proc near
  576.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  577.     inc    want_shutdown
  578.     inc    want_popup
  579.     call    try_popup
  580.     mov    al,0
  581.     xchg    al,want_shutdown    ; get and clear shutdown flag
  582.     cmp    al,0            ; if no longer set, shutdown successful
  583.     je    remov_successful
  584.     dec    want_popup        ; clear popup request
  585.     mov    al,AMIS_UNINST_TRYLATER    ; can't remove at this time
  586.     ret
  587. remov_successful:
  588.     mov    al,AMIS_UNINST_SAFE_OFF ; no resident remover, now disabled
  589.     mov    bx,0            ; seg of block to free (will be patched)
  590. ALTMPX$PSP equ word ptr ($-2)        ; magic name of word to be patched with
  591.                     ; actual memory block segment by TSR
  592.                     ; installation code
  593.     ret
  594. remov endp
  595.  
  596. ;-----------------------------------------------------------------------
  597. ; Declare the interrupt vectors hooked by the program, then set up the
  598. ; Alternate Multiplex Interrupt Spec handler
  599. ;
  600.     HOOKED_INTS 08h,13h,15h,25h,26h,28h
  601.  
  602.     HOTKEYS HK_INT15ENTRY
  603.     HOTKEY    HOTKEY_SCAN,HK_BOTHSHIFT,<HK_ANYCTRL OR HK_ANYALT>
  604.     HOTKEYS_DONE
  605.  
  606.     ALTMPX    'Ralf B','NOTE',VERSION_NUM,"Append notes to a file",,,API_popup,remov,Y,hotkey_list
  607.  
  608. ;-----------------------------------------------------------------------
  609. ; If we can't pop up immediately because DOS or disk I/O is busy, try to pop
  610. ; up on a subsequent timer tick
  611. ; We can save one byte by specifying the hardware reset handler set up by
  612. ; the ALTMPX macro above
  613. ;
  614. int08_handler proc far
  615. ISP_HEADER 08h,hw_reset_2Dh
  616.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  617.     pushf
  618.     call    ORIG_INT08h        ; chain to previous handler
  619.     call    try_popup        ; if need to pop up, try to do so now
  620.     iret
  621. int08_handler endp
  622.  
  623. ;-----------------------------------------------------------------------
  624. ; Can't pop up when disk is busy, so try to pop up on return
  625. ;
  626. int13_handler proc far
  627. ISP_HEADER 13h
  628.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  629.     sti                ; OK to interrupt here
  630.     inc    int13_busy
  631.     push    bp            ; now, restore original state of flags,
  632.     mov    bp,sp            ;   especially IF
  633.     push    word ptr [bp+6]        ; original flags before INT 13h
  634.     popf                ; restore original flags
  635.     pop    bp
  636.     pushf                ; simulate INT 13h
  637.     call    ORIG_INT13h
  638.     pushf                ; preserve returned flags
  639.     dec    int13_busy
  640.     popf                ; restore returned flags
  641.     call    try_popup        ; pop up if requested (saves all regs)
  642.     ret    2
  643. int13_handler endp
  644.  
  645. ;-----------------------------------------------------------------------
  646. ; Can't pop up when doing a raw read from disk, so try to pop up on return.
  647. ; We can save one byte by specifying the hardware reset handler set up by
  648. ; the INT 13h handler above
  649. ;
  650. int25_handler proc far
  651. ISP_HEADER 25h,hw_reset_13h
  652.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  653.     sti                ; OK to interrupt here
  654.     inc    int25_busy
  655.     push    bp            ; now, restore original state of flags,
  656.     mov    bp,sp            ;   especially IF
  657.     push    word ptr [bp+6]        ; original flags before INT 25h
  658.     popf                ; restore original flags
  659.     pop    bp
  660.     pushf                ; simulate INT 25h
  661.     call    ORIG_INT25h
  662.     pushf                ; preserve returned flags
  663.     dec    int25_busy
  664. int25_26_try_popup:
  665.     popf                ; restore returned flags
  666.     call    try_popup        ; pop up if requested (saves all regs)
  667.     ret
  668. int25_handler endp
  669.  
  670. ;-----------------------------------------------------------------------
  671. ; Can't pop up when doing a raw write to disk, so try to pop up on return.
  672. ; We can save one byte by specifying the hardware reset handler set up by
  673. ; the INT 13h handler above
  674. ;
  675. int26_handler proc far
  676. ISP_HEADER 26h,hw_reset_13h
  677.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  678.     sti                ; OK to interrupt here
  679.     inc    int26_busy
  680.     push    bp            ; now, restore original state of flags,
  681.     mov    bp,sp            ;   especially IF
  682.     push    word ptr [bp+6]        ; original flags before INT 26h
  683.     popf                ; restore original flags
  684.     pop    bp
  685.     pushf                ; simulate INT 26h
  686.     call    ORIG_INT26h
  687.     pushf                ; preserve returned flags
  688.     dec    int26_busy
  689.     jmp    int25_26_try_popup
  690. int26_handler endp
  691.  
  692. ;-----------------------------------------------------------------------
  693. ; Can't pop up when DOS is busy, but can do so during an INT 28h
  694. ;
  695. ISP_HEADER 28h
  696.     pushf
  697.     inc    popup_INT28
  698.     call    try_popup
  699.     dec    popup_INT28
  700.     popf                ; restore flags before chaining
  701.     jmp    ORIG_INT28h
  702.  
  703. ;-----------------------------------------------------------------------
  704. ; Hotkey checker.  Hotkey is Shift+Shift+Key, where Key is patched in at
  705. ; installation.
  706. ; We can save one byte by specifying the hardware reset handler set up by
  707. ; the INT 28h handler above
  708. ;
  709. IFDEF CUSTOM_HOTKEY_CODE
  710. int15_handler proc far
  711. ISP_HEADER 15h,hw_reset_28h
  712.     ASSUME    DS:NOTHING,ES:NOTHING,SS:NOTHING
  713.     pushf
  714.     sti                ; OK to be interrupted
  715.     cmp    ax,4F00h+HOTKEY_SCAN    ; can also patch with actual scan code
  716. hotkey_scancode equ byte ptr ($-2)    ;   at installation time
  717.     jne    not_hotkey
  718.     cmp    TSR_activated,0
  719.     jne    not_hotkey        ; ignore hotkey if already popped up
  720.     push    ds
  721.     push    ax
  722.     xor    ax,ax
  723.     mov    ds,ax
  724.     mov    al,ds:[417h]        ; get shift states
  725.     and    al,0Fh            ; mask out all but Shift/Ctrl/Alt
  726.     cmp    al,3            ; both Shift keys pressed?
  727.     pop    ax
  728.     pop    ds
  729.     jne    not_hotkey
  730.     ;
  731.     ; yes, we got our hotkey
  732.     ;
  733.     popf
  734.     call    attempt_popup        ; request a popup (preserves flags)
  735.     clc                ; throw out scan code
  736.     ret    2            ; and return so nobody else acts on it
  737. not_hotkey:
  738.     popf                ; restore flags
  739.     jmp    ORIG_INT15h
  740. int15_handler endp
  741.  
  742. ELSE
  743. hotkey_funcs label word            ; list of hotkey handlers
  744.     dw    attempt_popup
  745.  
  746.     HOTKEY_DISPATCHER AFTER,hotkey_funcs
  747. ENDIF
  748.  
  749. TSRcodeEnd@
  750.  
  751. ;-----------------------------------------------------------------------
  752.  
  753. _TEXT SEGMENT 'CODE'
  754.     ASSUME cs:_TEXT,ds:NOTHING,es:NOTHING,ss:NOTHING
  755.  
  756. banner              db 'NOTE v',VERSION_STR,'  Public Domain 1992 Ralf Brown',13,10,'$'
  757. usage_msg     db "Usage:",9,"NOTE -Ifile",9,"Install using <file> as notepad",13,10
  758.          db 9,"NOTE -R",9,9,"Remove from memory",13,10
  759.          db "$"
  760. hotkey_msg     db "Press Shift-Shift-",HOTKEY_NAME," to pop up",13,10,"$"
  761. no_hotkey_msg     db "Hotkey is not available on this machine",13,10,"$"
  762. hotkey_used_msg     db "Hotkey is already in use.",13,10,"$"
  763. installed_msg     db "Installed.",13,10,"$"
  764. already_inst_msg db 13,10,"Already installed.",13,10,"$"
  765. cant_remove_msg  db "Can't remove from memory.",13,10,"$"
  766. uninstalled_msg  db "Removed.",13,10,"$"
  767. cant_access_msg     db "Unable to open or create notepad file",13,10,"$"
  768.  
  769. filename_len equ 80
  770. filename_buf    db filename_len dup (?)
  771.  
  772.  
  773.  
  774.     @Startup2    Y
  775.     push    ds
  776.     pop    es
  777.     ASSUME    ES:_INIT
  778.     push    cs
  779.     pop    ds
  780.     ASSUME    DS:_TEXT
  781.     ;
  782.     ; say hello 
  783.     ;
  784.     DISPLAY_STRING banner
  785.     mov    bx,1000h        ; set memory block to 64K
  786.     mov    ah,4Ah
  787.     int    21h
  788.     mov    si,81h            ; SI -> command line
  789.     cld                ; ensure proper direction for string ops
  790. cmdline_loop:
  791.     lodsb_es
  792.     cmp    al,' '            ; skip blanks and tabs on commandline
  793.     je    cmdline_loop
  794.     cmp    al,9
  795.     je    cmdline_loop
  796.     cmp    al,'-'
  797.     je    got_cmdline_switch
  798. bad_cmdline:
  799.     jmp    usage
  800. got_cmdline_switch:
  801.     lodsb_es            ; get next character
  802.     and    al,0DFh            ; force to uppercase
  803.     cmp    al,'R'
  804.     jne    not_removing
  805.     jmp    removing
  806. not_removing:
  807.     cmp    al,'I'
  808.     jne    bad_cmdline
  809. installing:
  810.     ;
  811.     ; place any necessary pre-initialization here
  812.     ;
  813.     mov    di,offset _TEXT:filename_buf
  814.     mov    dx,di            ; remember start of filename
  815.     mov    cx,filename_len
  816.     push    es
  817.     pop    ds
  818.     ASSUME    DS:_INIT
  819.     push    cs
  820.     pop    es
  821.     ASSUME    ES:_TEXT
  822. copy_filename_loop:
  823.     lodsb
  824.     cmp    al,' '
  825.     jb    copy_filename_done
  826.     stosb
  827.     loop    copy_filename_loop
  828. copy_filename_done:
  829.     mov    al,0
  830.     stosb
  831.     push    cs
  832.     pop    ds
  833.     ASSUME    DS:_TEXT
  834.     mov    ax,3DC1h        ; open, no-inherit/DENYNONE/write-only
  835.     int    21h
  836.     jnc    open_successful
  837.     mov    ax,3C00h        ; if unable to open, try creating file
  838.     xor    cx,cx            ; no special attributes
  839.     int    21h
  840.     jnc    create_successful
  841.     mov    dx,offset _TEXT:cant_access_msg
  842.     jmp    exit_with_error
  843. open_successful:
  844. create_successful:
  845.     push    cs
  846.     pop    ds            ; restore DS
  847.     ASSUME    DS:_TEXT
  848.     mov    bx,ax
  849.     mov    ah,3Eh            ; close the file again; we now know
  850.     int    21h            ;   we can access it
  851.     ;
  852.     ; find out whether keyboard intercept is available
  853.     ;
  854.     stc
  855.     mov    ah,0C0h
  856.     int    15h            ; get ROM BIOS configuration data
  857.     ASSUME    ES:NOTHING
  858.     mov    dx,offset _TEXT:no_hotkey_msg
  859.     jc    no_kbd_intercept
  860.     test    byte ptr es:[bx+5],10h    ; have keyboard intercept?
  861.     jz    no_kbd_intercept
  862.     mov    dx,offset _TEXT:hotkey_msg
  863. no_kbd_intercept:
  864.     mov    ah,9
  865.     int    21h
  866.     ;
  867.     ; get and store pointers to DOS busy flags
  868.     ;
  869.     mov    ah,34h            ; get address of InDOS flag
  870.     int    21h
  871.     ASSUME    ES:NOTHING
  872.     mov    ds,TGROUP@
  873.     ASSUME    DS:TGROUP
  874.     mov    word ptr TGROUP:INDOS_ptr,bx
  875.     mov    word ptr TGROUP:INDOS_ptr+2,es
  876.     push    ds
  877.     mov    ax,5D06h        ; get address of CriticalError flag
  878.     int    21h
  879.     ASSUME    DS:NOTHING
  880.     mov    dx,ds
  881.     pop    ds
  882.     ASSUME    DS:TGROUP
  883.     mov    word ptr TGROUP:CRITERR_ptr+2,dx
  884.         mov     word ptr TGROUP:CRITERR_ptr,si
  885.     ;
  886.     ; one last check: is there a hotkey conflict?
  887.     ;
  888.     IF_HOTKEY_USED    hotkey_in_use
  889.     ;
  890.     ; now go install the TSR
  891.     ;
  892.     push    cs
  893.     pop    ds
  894.     ASSUME    DS:_TEXT
  895. ;note: add TOPMEM following BEST to make TSR load at top of memory
  896.     INSTALL_TSR ,BEST,,inst_patch,already_installed
  897.  
  898. hotkey_in_use:
  899.     push    cs
  900.     pop    ds
  901.     ASSUME    DS:_TEXT
  902.     mov    dx,offset hotkey_used_msg
  903.     jmp short exit_with_error
  904.  
  905. removing:
  906.     ASSUME    DS:_TEXT
  907.     UNINSTALL cant_uninstall
  908.     push    cs
  909.     pop    ds
  910.     ASSUME    DS:_TEXT
  911.     DISPLAY_STRING uninstalled_msg
  912.         mov     ax,4C00h
  913.     int    21h
  914.  
  915. already_installed:
  916.     mov    dx,offset _TEXT:already_inst_msg
  917.     jmp short exit_with_error
  918.  
  919. usage:
  920.     ASSUME    DS:_TEXT
  921.     mov    dx,offset _TEXT:usage_msg
  922.     jmp short exit_with_error
  923.  
  924. cant_uninstall:
  925.     mov    dx,offset _TEXT:cant_remove_msg
  926. exit_with_error:
  927.     push    cs
  928.     pop    ds
  929.     ASSUME    DS:_TEXT
  930.     mov    ah,9
  931.     int    21h
  932.     mov    ax,4C01h
  933.     int    21h
  934.  
  935. inst_patch:
  936.     ASSUME    DS:NOTHING
  937.     push    ds
  938.         push    es
  939.         mov     es,ax
  940.     ASSUME    ES:TGROUP
  941.     ;
  942.     ; close all files which will not be used by the TSR
  943.     ;
  944.     mov    bx,0            ; for this TSR, don't need handles 0-4
  945. close_file_loop:
  946.     mov    ah,3Eh
  947.     int    21h
  948.     inc    bx
  949.     cmp    bx,4
  950.     jbe    close_file_loop
  951.     ;
  952.     ; now copy the PSP into the resident portion
  953.     ;
  954.     mov    ds,__psp
  955.     ASSUME    DS:_INIT
  956.     xor    si,si
  957.     xor    di,di
  958.     mov    cx,size TSR_PSP
  959.     cld
  960.     rep    movsb
  961.     mov    es:[36h],es        ; adjust JFT pointer in copied PSP
  962.     mov    bx,es
  963.     mov    ah,50h            ; set PSP segment so TSR owns file
  964.     int    21h
  965.     push    cs
  966.     pop    ds
  967.     ASSUME    DS:_TEXT
  968.     mov    dx,offset _TEXT:filename_buf
  969.         mov     ax,3DC1h                ; open, no-inherit/DENYNONE/write-only
  970.     int    21h
  971.     jnc    reopen_successful
  972.     xor    ax,ax            ; point at a closed handle
  973. reopen_successful:
  974.     mov    TGROUP:notefile_handle,ax
  975.     mov    bx,ax
  976.     xor    cx,cx
  977.     xor    dx,dx
  978.     mov    ax,4202h        ; position to end of file
  979.     int    21h
  980.     mov    ah,50h            ; restore PSP segment
  981.     mov    bx,__psp
  982.     mov    ds,bx
  983.     ASSUME    DS:_INIT
  984.     int    21h
  985.     ;
  986.     ; now, zero out the JFT in our PSP so that the exit won't close
  987.     ; the files that the TSR does need
  988.     ;
  989.     mov    cx,ds:[0032h]        ; size of JFT
  990.     les    di,ds:[0034h]        ; pointer to JFT
  991.     mov    al,0FFh            ; closed-file flag
  992.     rep    stosb
  993.     pop    es
  994.     ASSUME    ES:NOTHING
  995.     ;
  996.     ; finally, announce that we are installed
  997.     ;
  998.     push    cs
  999.     pop    ds
  1000.     ASSUME    DS:_TEXT
  1001.     DISPLAY_STRING installed_msg
  1002.     pop    ds
  1003.     ASSUME    DS:NOTHING
  1004.     ret
  1005.  
  1006. _TEXT ENDS
  1007.  
  1008.      end INIT
  1009.  
  1010.